package simulator;

import java.math.BigInteger;

class fetch{

}

class decode{
	
	
}

class Execute{
	int change_to_decimal(String Binary){
		BigInteger Temp = new BigInteger(Binary,2);	
		return Integer.parseInt(Temp.toString());
	}
	
	String change_to_Binary(int var){
		BigInteger Temp = new BigInteger(String.valueOf(var));
		return Temp.toString(2);
	}
	
	int calculate(String IR, Memory memory){
		int addr =0;		
		addr = change_to_decimal(IR.substring(10));
		
		if(IR.substring(7,7)=="1"){
			addr = change_to_decimal(String.valueOf(Register.X0))+addr;
			if(IR.substring(6, 6)=="1"){
				addr = change_to_decimal(String.valueOf(memory.read(addr)));
			}
		}
		return addr;
	}
	
	char[] get_C_r(char[] R,Memory memory){
		char[] value;
		value = memory.read(change_to_decimal(String.valueOf(R)));
		return value;
	}
	public boolean OP_HALT(String IR)//HALT operation
	{
		return true;
	}
	
/*OP_LD:	Load operation RegType: 
	 * 1-Load Register From Memory 
	 * 2-Load Index Register from Memory
	 * 3-Load Register with Address
	 * */
	public String OP_LD(String IR, Memory memory, int RegType ){
		try{
			char[] get=null;
			int addr = calculate(IR,memory);
			if (RegType==1){
				get = memory.read(addr);
				switch(IR.substring(8, 9)){
				case "00": Register.R0 = get;
				case "01": Register.R1 = get;
				case "10": Register.R2 = get;
				case "11": Register.R2 = get;
			}
			}
			else if(RegType==2){
				get = memory.read(addr);
				Register.X0 = get;
			}
			else if(RegType==3){
				switch(IR.substring(8, 9)){
				case "00": Register.R0 = Integer.toBinaryString(addr).toCharArray();
				case "01": Register.R1 = Integer.toBinaryString(addr).toCharArray();
				case "10": Register.R2 = Integer.toBinaryString(addr).toCharArray();
				case "11": Register.R2 = Integer.toBinaryString(addr).toCharArray();
				}
			}
			return "0011";
		}
		catch(Exception ex){
			return "0000";
		}
	}
	
/*OP_ST:	Store operation RegType:
	 * 1:Store Register to Memory
	 * 2:Store Index Register to Memory
	 * */
	public String OP_ST(String IR, Memory memory, int RegType){
		try{
			int addr = calculate(IR,memory);
			
			if(RegType == 1){
				switch(IR.substring(8, 9)){
				case "00":	memory.write(addr, Register.R0);
				case "01":	memory.write(addr, Register.R1);
				case "10":	memory.write(addr, Register.R2);
				case "11":	memory.write(addr, Register.R3);
				}
			}
			
			else if (RegType == 2){
				memory.write(addr, Register.X0);
			}
			
			return 	"0011";
		}
		catch(Exception ex){
			return	"0000";
		}
	}

/*OP_JP:	Jump operation JumpType:
 * 1:Jump if Zero
 * 2:Jump if not Equal
 * 3:Jump if Condition Code
 * 4:Unconditional Jump To Address
 * 5:Jump and Save Return Address
 * */
	public String OP_JP(String IR, Memory memory, int JumpType){
		try{
			int addr =calculate(IR,memory);
			
			if(JumpType == 1){
				char[] judge=null;
				switch(IR.substring(8, 9)){
				case "00":	judge = Register.R0;
				case "01":	judge = Register.R1;
				case "10":	judge = Register.R2;
				case "11":	judge = Register.R3;
				}
				
				if(change_to_decimal(String.valueOf(judge))==0){
					Register.PC = change_to_Binary(addr).toCharArray();
				}
				else{			
					Register.PC = change_to_Binary(change_to_decimal(String.valueOf(Register.PC))+1).toCharArray();
				}
			}
			
			else if(JumpType == 2){
				char[] judge=null;
				switch(IR.substring(8, 9)){
				case "00":	judge = Register.R0;
				case "01":	judge = Register.R1;
				case "10":	judge = Register.R2;
				case "11":	judge = Register.R3;
				}
				if(change_to_decimal(String.valueOf(judge))!=0){
					Register.PC = change_to_Binary(addr).toCharArray();
				}
				else{			
					Register.PC = change_to_Binary(change_to_decimal(String.valueOf(Register.PC))+1).toCharArray();
				}
			}
			
			else if(JumpType == 3){
				if(change_to_decimal(String.valueOf(Register.CC))==0){
					Register.PC = change_to_Binary(addr).toCharArray();
				}
				else{			
					Register.PC = change_to_Binary(change_to_decimal(String.valueOf(Register.PC))+1).toCharArray();
				}
			}
			
			else if(JumpType == 4){
				Register.PC = change_to_Binary(addr).toCharArray();
			}
			
			else if(JumpType == 5){
				Register.R3 = change_to_Binary(change_to_decimal(String.valueOf(Register.PC))+1).toCharArray();
				Register.PC = change_to_Binary(addr).toCharArray();
			}
			
			return "0011";
		}
		catch(Exception ex){
			return "0000";
		}
	}

/*OP_RFS:	RFS Immed Return From Subroutine W/ return code in Inned Portion(optional) stored in R0
 * */
	public String OP_RFS(String IR, Memory memory){
		try{
			Register.R0 = IR.substring(10).toCharArray();
			Register.PC = memory.read(change_to_decimal(String.valueOf(Register.R3)));
			return "0111";
		}
		catch(Exception ex){
			return "0000";
		}
	}
	
/*OP_SOB:	SOB Subtract One And Branch
 * */
	public String OP_SOB(String IR, Memory memory){
		try{
			
			switch(IR.substring(8, 9)){
			case "00":	Register.R0= String.valueOf(get_C_r(Register.R0,memory));
			case "01":	judge = Register.R1;
			case "10":	judge = Register.R2;
			case "11":	judge = Register.R3;
			}
			return "0111";
		}
		catch(Exception ex){
			return "0000";
		}
	}




}
public class Processor {
	
	public static void main(String[] args){
		Memory memory = new Memory();
		
		Register.MAR=Register.PC.clone(); 
		//PC->MAR
		Register.MBR = memory.read(Integer.parseInt(Register.MAR.toString()));
		//Memory(MAR)->MBR
		Register.IR = Register.MBR.clone();
		//MBR->IR
		
		//get operation code
		Execute ex = new Execute();
		switch(Register.IR.toString().substring(0, 5)){
		
		case "000000": Register.poweron= ex.OP_HALT(Register.IR.toString()); //HLT
		
		//case "030":	//TRAP r; this will be used in the second part of this project!
			
		case "000001":  Register.MFR = ex.OP_LD(String.valueOf(Register.IR), memory, 1).toCharArray();	//LDR
		case "000002":	Register.MFR = ex.OP_ST(String.valueOf(Register.IR), memory, 1).toCharArray();	//STR
		case "000003":	Register.MFR = ex.OP_LD(String.valueOf(Register.IR), memory, 3).toCharArray();	//LDA
		case "000041":	Register.MFR = ex.OP_LD(String.valueOf(Register.IR), memory, 2).toCharArray();	//LDX
		case "000042":	Register.MFR = ex.OP_ST(String.valueOf(Register.IR), memory, 2).toCharArray();	//STX
		case "000010":	Register.MFR = ex.OP_JP(String.valueOf(Register.IR), memory, 1).toCharArray();//JZ
		case "000011":	Register.MFR = ex.OP_JP(String.valueOf(Register.IR), memory, 2).toCharArray();//JNE
		case "000012":	Register.MFR = ex.OP_JP(String.valueOf(Register.IR), memory, 3).toCharArray();//JCC
		case "000013": 	Register.MFR = ex.OP_JP(String.valueOf(Register.IR), memory, 4).toCharArray();//JMP
		case "000014": 	Register.MFR = ex.OP_JP(String.valueOf(Register.IR), memory, 5).toCharArray();//JSR
		case "000015": 	//RFS
		case "000016": 	//SOB
		case "000004": //ADD
		case "000005": //SUB
		case "000006": //AIR
		case "000007": //SIR
		case "000020": //MUL
		case "000021": //DIV
		case "000022": //TST
		case "000023": //AND
		case "000024": //OR
		case "000025": //NOT
		case "000031": //SRC
		case "000032": //RRC
		case "000061": //IN
		case "000062": //OUT
		case "000063": //CHK
		case "000033": //FADD
		case "000034": //FSUB
		case "000035": //VADD
		case "000036": //VSUB
		case "000037": //CNVRTF
		default: Register.MFR = "0011".toCharArray();
		}
	}

}
